﻿using DotNet.Utilities.ConsoleHelper;
using PropertyChanged;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using WPFPractice.Utils;
using WPFTemplateLib.WpfHelpers;

namespace WPFPractice.Windows
{
    public partial class WinTaskTester : Window
    {
        private TaskTesterViewModel _vm;

        public WinTaskTester()
        {
            InitializeComponent();
            DataContext = _vm = new TaskTesterViewModel();
        }
    }

    [AddINotifyPropertyChangedInterface]
    public class TaskTesterViewModel : MyBindableBase
    {
        #region 成员

        /// <summary>
        /// 休眠任务的取消令牌
        /// </summary>
        private CancellationTokenSource _sleepCts;

        #endregion

        #region Bindable

        /// <summary>
        /// 任务数量
        /// </summary>
        public int TaskNum { get; set; } = 5;

        /// <summary>
        /// 每个任务执行的计算轮数
        /// </summary>
        public int CalculateNum { get; set; } = 6;

        /// <summary>
        /// 整个任务的超时时间（分钟）
        /// </summary>
        public int WholeTimeout { get; set; } = 5;

        /// <summary>
        /// 每次休眠毫秒数
        /// </summary>
        public int SleepMillisecond { get; set; } = 500;

        /// <summary>
        /// 是否输出休眠间隙日志
        /// </summary>
        public bool IsShowSleepGapLog { get; set; } = true;

        /// <summary>
        /// 是否开启专用线程
        /// </summary>
        public bool IsCreateNewThread { get; set; } = true;

        /// <summary>
        /// 休眠类型集合
        /// </summary>
        public ObservableCollection<SleepType> SleepTypes { get; set; } = new ObservableCollection<SleepType>()
        {
            new SleepType(){Tag = 1, Description = "Thread.Sleep", IsSelected = true},
            new SleepType(){Tag = 2, Description = "Task.Delay"},
            new SleepType(){Tag = 3, Description = "await Task.Delay"},
        };

        /// <summary>
        /// 线程池最小线程数（工作线程）
        /// </summary>
        public int MinThreads1 { get; set; }

        /// <summary>
        /// 线程池最小线程数（完成端口线程）
        /// </summary>
        public int MinThreads2 { get; set; }

        /// <summary>
        /// 线程池最大线程数（工作线程）
        /// </summary>
        public int MaxThreads1 { get; set; }

        /// <summary>
        /// 线程池最大线程数（完成端口线程）
        /// </summary>
        public int MaxThreads2 { get; set; }

        #endregion

        #region Command

        /// <summary>
        /// 命令：启动普通任务
        /// </summary>
        public ICommand StartTasksCmd { get; set; }

        /// <summary>
        /// 命令：启动休眠任务
        /// </summary>
        public ICommand StartSleepTaskCmd { get; set; }

        /// <summary>
        /// 命令：停止休眠任务
        /// </summary>
        public ICommand StopSleepTaskCmd { get; set; }

        /// <summary>
        /// 命令：查询线程池最小线程数
        /// </summary>
        public ICommand QueryMinThreadsCmd { get; set; }

        /// <summary>
        /// 命令：查询线程池最大线程数
        /// </summary>
        public ICommand QueryMaxThreadsCmd { get; set; }

        /// <summary>
        /// 命令：设置线程池最小线程数
        /// </summary>
        public ICommand SetMinThreadsCmd { get; set; }

        /// <summary>
        /// 命令：设置线程池最大线程数
        /// </summary>
        public ICommand SetMaxThreadsCmd { get; set; }

        #endregion

        public TaskTesterViewModel()
        {
            SetCommandMethod();

            InitValue();

            Console.SetOut(new ConsoleWriter(s =>
            {
                ShowInfoUc(s);
            }));
        }

        /// <summary>
        /// 数据初始化
        /// </summary>
        private void InitValue()
        {
            ShowInfoUc("测试 C# Task");
        }

        /// <summary>
        /// 命令方法赋值(在构造函数中调用)
        /// </summary>
        private void SetCommandMethod()
        {
            StartTasksCmd ??= new RelayCommand(o => true, async o =>
            {
                ShowInfoUc($"[{nameof(StartTasksCmd)}]命令触发。{GetThreadInfo()}");
                _ = Task.Run(async () =>
                {
                    ShowInfoUc($"按钮内任务启动，将创建【{TaskNum}】个 Task。{GetThreadInfo()}");
                    Stopwatch sw = Stopwatch.StartNew();
                    List<Task> tasks = new List<Task>();
                    for (int i = 0; i < TaskNum; i++)
                    {
                        string name = $"任务{i + 1}";
                        await Task.Delay(100);
                        Task task = Task.Run(() =>
                        {
                            try
                            {
                                ShowInfoUc($"{name} 启动，将进行[{CalculateNum}]轮计算，{GetThreadInfo()}");
                                Stopwatch swTotal = Stopwatch.StartNew();
                                for (int j = 0; j < CalculateNum; j++)
                                {
                                    Stopwatch swCurrent = Stopwatch.StartNew();
                                    GetSum(999999999);
                                    swCurrent.Stop();
                                    ShowInfoUc($"{name} 完成第[{j + 1}]轮计算，耗时：{swCurrent.Elapsed}");
                                }

                                swTotal.Stop();
                                ShowInfoUc($"{name} 结束，总耗时：{swTotal.Elapsed}");
                            }
                            catch (Exception ex)
                            {
                                ShowInfoUc($"{name} 异常：{ex.Message}");
                            }
                        });

                        tasks.Add(task);
                    }

                    TimeSpan timeSpan = TimeSpan.FromMinutes(WholeTimeout);
                    Task.WaitAll(tasks.ToArray(), timeSpan);
                    sw.Stop();
                    if (tasks.All(x => x.IsCompleted))
                    {
                        ShowInfoUc($"【{TaskNum}】个 Task 全部结束，成功[{tasks.Count(x => x.IsCompletedSuccessfully)}]个，耗时【{sw.Elapsed}】。{GetThreadInfo()}", true);
                    }
                    else
                    {
                        ShowInfoUc($"(超时时间[{timeSpan}]已过)【{TaskNum}】个 Task 完成了[{tasks.Count(x => x.IsCompleted)}]个，成功[{tasks.Count(x => x.IsCompletedSuccessfully)}]个。{GetThreadInfo()}", true);
                    }

                    _sleepCts?.Cancel();
                });
            });

            StartSleepTaskCmd ??= new RelayCommand(o => true, o =>
            {
                ShowInfoUc($"[{nameof(StartSleepTaskCmd)}]命令触发。{GetThreadInfo()}");
                _sleepCts = new CancellationTokenSource();
                _sleepCts.Token.Register(() =>
                {
                    ShowInfoUc($"休眠任务已停止。{GetThreadInfo()}");
                });

                TaskCreationOptions creationOptions = TaskCreationOptions.None;
                if (IsCreateNewThread)
                {
                    creationOptions = TaskCreationOptions.LongRunning;
                }

                _ = Task.Factory.StartNew(async () =>
                {
                    ShowInfoUc($"按钮内任务启动，即将执行休眠任务。{GetThreadInfo()}");
                    while (!_sleepCts.Token.IsCancellationRequested)
                    {
                        int tag = SleepTypes.FirstOrDefault(x => x.IsSelected)?.Tag ?? 1;
                        switch (tag)
                        {
                            case 1:
                            default:
                                Thread.Sleep(SleepMillisecond);
                                break;
                            case 2:
                                Task.Delay(SleepMillisecond);
                                break;
                            case 3:
                                await Task.Delay(SleepMillisecond);
                                break;

                        }

                        if (IsShowSleepGapLog)
                        {
                            ShowInfoUc($"休眠任务间隙。{GetThreadInfo()}");
                        }
                        Thread.Sleep(0);
                    }
                }, _sleepCts.Token, creationOptions, TaskScheduler.Default);
            });

            StopSleepTaskCmd ??= new RelayCommand(o => true, o =>
            {
                ShowInfoUc($"[{nameof(StopSleepTaskCmd)}]命令触发。{GetThreadInfo()}");
                _sleepCts?.Cancel();
            });

            QueryMinThreadsCmd ??= new RelayCommand(o => true, o =>
            {
                ShowInfoUc($"[{nameof(QueryMinThreadsCmd)}]命令触发。{GetThreadInfo()}");
                ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
                MinThreads1 = workerThreads;
                MinThreads1 = completionPortThreads;
            });

            QueryMaxThreadsCmd ??= new RelayCommand(o => true, o =>
            {
                ShowInfoUc($"[{nameof(QueryMaxThreadsCmd)}]命令触发。{GetThreadInfo()}");
                ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
                MaxThreads1 = workerThreads;
                MaxThreads2 = completionPortThreads;
            });

            SetMinThreadsCmd ??= new RelayCommand(o => true, o =>
            {
                ShowInfoUc($"[{nameof(SetMinThreadsCmd)}]命令触发。{GetThreadInfo()}");
                bool isSuccess = ThreadPool.SetMinThreads(MinThreads1, MinThreads2);
                ShowInfoUc($"设置最小线程数结果：{isSuccess}");
            });

            SetMaxThreadsCmd ??= new RelayCommand(o => true, o =>
            {
                ShowInfoUc($"[{nameof(SetMaxThreadsCmd)}]命令触发。{GetThreadInfo()}");
                bool isSuccess = ThreadPool.SetMaxThreads(MaxThreads1, MaxThreads2);
                ShowInfoUc($"设置最大线程数结果：{isSuccess}");
            });
        }

        #region Method

        private long GetSum(long count = 1_0000_0000)
        {
            long sum = 0;
            for (int i = 0; i < count; i++)
            {
                sum += i;
            }

            return sum;
        }

        private string GetThreadInfo()
        {
            return $"线程号[{Thread.CurrentThread.ManagedThreadId}]，是否是线程池线程[{Thread.CurrentThread.IsThreadPoolThread}]，是否是后台线程[{Thread.CurrentThread.IsBackground}]";
        }

        #endregion
    }

    /// <summary>
    /// 休眠实现方式
    /// </summary>
    [AddINotifyPropertyChangedInterface]
    public class SleepType
    {
        /// <summary>
        /// 标识
        /// </summary>
        public int Tag { get; set; }

        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// 是否选择
        /// </summary>
        public bool IsSelected { get; set; }
    }
}
